/* =======================================================================================================
 *              <<Branchitech>> Software License v1.0
 * =======================================================================================================

 * 版权所有  (c) 2005 <<Branchitech>>

 * Copyright (c) 2005 <<Branchitech>> All rights reserved.

 * <<Branchitech>> 对由其自主开发或和他人共同开发的所有内容和服务拥有全部知识产权，

 * 此等知识产权受到适用的知识产权（版权-著作权、商标权、专利权、非专利技术等）法律

 * 和其他法律及相关国际条约的保护。

 * 未经授权许可，任何个人、单位、组织等不得对本公司的软件产品、程序（包括各种可执行文件、源码、其他文件、

 * 开发文档、技术手册等）进行编译、反编译、再编译、出售、复制、传播、破坏、仿制、非法占有等。

 * 本公司保留一切追究侵犯人法律责任之权利。其他语言之版权声明以此汉语版为准。

 * www.<<Branchitech>>.com

 * ======================================================================================================
 */
package net.zoneland.knowledge.service.impl;

import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.StringUtils;
import org.apache.lucene.util.NamedThreadFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import net.zoneland.knowledge.notice.WorkNotice;
import net.zoneland.knowledge.service.NotifyService;

/**
 * 浙江移动统一通知实现.
 * @version $Id$
 * @author zhoumiaoqian
 * @since  2020年3月16日
 */
@Service
public class NotifyServiceImpl implements NotifyService {
    /** 日志. */
    private static final Logger LOGGER = LoggerFactory.getLogger(NotifyServiceImpl.class);

    /**
     * 默认的http请求头.
     */
    public static final HttpHeaders JSON_HTTP_HEADERS = new HttpHeaders();
    static {
        JSON_HTTP_HEADERS.setContentType(MediaType.APPLICATION_JSON);
    }

    /**
     * 线程池.
     */
    private static final ExecutorService EXECUTOR_SERVICE =
        new ThreadPoolExecutor(4, 8, 0,
            TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new NamedThreadFactory("notify"),
            new ThreadPoolExecutor.AbortPolicy());

    /**
     * 通知模式，默认为邮件形式.
     * 1邮件；2短信；3邮件+短信
     */
    private static final int NOTICE_MODE_EMAIL = 1;
    /**
     * 通知模型.
     */
    private static final int NOTICE_MODE_SMS = 2;

    /**
     * 接受者类型：1,userid;2邮箱地址;3短信提醒.
     */
    private static final int RECIPIENT_TYPE_USERID = 1;
    /**
     * 接收者类型.
     */
    private static final int RECIPIENT_TYPE_EMAIL = 2;
    /**
     * 接收者类型.
     */
    private static final int RECIPIENT_TYPE_SMS = 3;

    /**
     * 发送人.
     */
    private static final String SENDER = "admin@zj.chinamobile.com";
    /**
     * 发送类型.
     */
    private static final int SENDER_TYPE = 2;

    /**
     * 统一通知中配置的系统ID.
     */
    @Value("${app_name:appName}")
    private String SYSTEM_ID;

    /**
     * 短信发送者.
     */
    private static final String MSG_SENDER = "10658288";

    /**
     * 通知ws接口.
     */
    @Value("${unimessage.endPoint}")
    private String uniMessageUrl;

    /**
     * rest请求模板.
     */
    @Autowired
    private RestTemplate restTemplate;

    /**
     * json工具类.
     */
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * {@inheritDoc}
     * @see net.zoneland.knowledge.service.NotifyService#notifyByEmail(String[], String, String)
     */
    @Override
    public void notifyByEmail(String[] reciever, String title, String content) {
        final WorkNotice notice = this.buildWorkNotice(reciever, title, content, NOTICE_MODE_EMAIL,
            StringUtils.contains(reciever[0], "@") ? RECIPIENT_TYPE_EMAIL : RECIPIENT_TYPE_USERID);
        notice.setSender(SENDER);
        notice.setSenderType(SENDER_TYPE);
        sendWorkNotcie(notice);
    }

    /**
     * 构造通知.
     * @param reciever 接收者
     * @param title 标题
     * @param content 内容
     * @param noticeModel 通知模式
     * @param recipientType 发送类型
     * @return 发送信息对象
     */
    protected WorkNotice buildWorkNotice(String[] reciever, String title, String content, int noticeModel, int recipientType) {
        LOGGER.info("准备发送{}通知:subject[{}]targetId[{}]", (noticeModel == NOTICE_MODE_SMS ? "短信" : "邮件"), content, reciever);
        WorkNotice workNotice = new WorkNotice();

        // 设置链接地址
        workNotice.setNoticeContent(content);

        workNotice.setNoticeTitle(title);
        if (StringUtils.isEmpty(workNotice.getNoticeTitle())) {
            //如果标题为空，则用内容当标题
            workNotice.setNoticeTitle(workNotice.getNoticeContent());
        }
        workNotice.setRecipients(reciever);
        workNotice.setNoticeMode(noticeModel);
        workNotice.setRecipientType(recipientType);
        // 即时发送
        workNotice.setScheduleTime(0);
        workNotice.setSourceSystemId(SYSTEM_ID);

        return workNotice;
    }

    /**
     * {@inheritDoc}
     * @see net.zoneland.knowledge.service.NotifyService#notifyBySms(String[], String)
     */
    @Override
    public void notifyBySms(String[] reciever, String content) {
        final WorkNotice notice = this.buildWorkNotice(reciever, "", content, NOTICE_MODE_SMS, 3);
        notice.setSender(MSG_SENDER);
        notice.setSenderType(RECIPIENT_TYPE_SMS);
        sendWorkNotcie(notice);
    }


    /**
     *  用户id通知短信。
     * @param userId  用户id
     * @param content 内容
     */
    @Override
    public void userIdNotifyBySms(String[] userId, String content) {
        final WorkNotice notice = this.buildWorkNotice(userId, "", content, NOTICE_MODE_SMS, RECIPIENT_TYPE_USERID);
        notice.setSender(MSG_SENDER);
        notice.setSenderType(RECIPIENT_TYPE_SMS);
        sendWorkNotcie(notice);
    }

    /**
     * 发送通知.
     * @param workNotice 通知对象
     */
    protected void sendWorkNotcie(final WorkNotice workNotice) {
        try {
            // 创建一个线程去调用这个webService
            EXECUTOR_SERVICE.execute(() -> {
                try {
                    final String content = objectMapper.writeValueAsString(workNotice);
                    final HttpEntity<String> request = new HttpEntity<>(content, JSON_HTTP_HEADERS);
                    final ResponseEntity<String> response = restTemplate.postForEntity(uniMessageUrl, request, String.class);
                    final String body = Optional.ofNullable(response)
                            .filter(it -> it.getStatusCode() == HttpStatus.OK)
                            .map(ResponseEntity::getBody)
                            .orElse(StringUtils.EMPTY);
                    if (LOGGER.isInfoEnabled()) {
                        LOGGER.info("sendWorkNotice result:[{}]", body);
                    }
                } catch (JsonProcessingException e) {
                    LOGGER.error("JsonProcessingException, mailInfo:{}", workNotice, e);
                }
            });
        } catch (Exception e) {
            LOGGER.error("发送同一通知出错, mailInfo:{}", workNotice, e);
        }
    }
}
